package com.yb.custom.annotation.log.filter;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.yb.custom.annotation.log.controller.vo.ResultVO;
import com.yb.custom.annotation.log.exception.CustomException;
import com.yb.custom.annotation.log.util.IpUtils;
import com.yb.custom.annotation.log.util.JwtUtils;
import com.yb.custom.annotation.log.util.LoginUserUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Objects;

/**
 * 简化后过滤器,含有默认密码登录校验和响应json错误提示信息(推荐)
 * OncePerRequestFilter这个过滤器,请求只会过滤一次
 * 这个对于认证来说是比较好的,不用担心多次经过同一个过滤器而导致的多次认证
 *
 * @author yangbiao
 * @date 2022/3/1
 */
@Slf4j
@Component
public class MyAuthFilter extends OncePerRequestFilter {

    /**
     * 自定义认证过滤器
     *
     * @param request
     * @param response
     * @param filterChain
     * @throws ServletException
     * @throws IOException
     */
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        try {
            //获取请求头里的token信息
            String jwtToken = request.getHeader(JwtUtils.AUTHORIZATION);
            if (StrUtil.isBlank(jwtToken)) {
                jwtToken = request.getParameter("accessToken");
            }
            //判断token是否存在以及token的合法性
            //LoginUserUtils.LoginUser loginUser = JwtUtils.verifyAccessToken(jwtToken);
            //默认验证token通过
            LoginUserUtils.LoginUser loginUser = new LoginUserUtils.LoginUser();
            //判断并处理业务(登录请求即使带了有效的token也不处理token信息)
            if (Objects.nonNull(loginUser)) {
                //获取请求路径
                final String servletPath = request.getServletPath();
                final String method = request.getMethod();
                loginUser.setRequestPath(servletPath);
                loginUser.setRequestType(method);
                loginUser.setRequestIp(IpUtils.getIpAddr(request));

                loginUser.setUserId("test01");
                loginUser.setFullName("张三");
                loginUser.setUsername("jack@163.com");
                loginUser.setUserOrganization("宇宙科技有限公司");
                loginUser.setUserDepartment("科技部");
                loginUser.setUserPosition("星球开发");
                loginUser.setUserRole("开发经理");

//                //由于没有使用redis所以这里就不使用jti来让token有状态和快速失效,使用的是原生态的无状态
//                Set<GrantedAuthority> authoritySet = null;
//                //获取权限集合(不使用角色来认证接口,可新添加一个权限来替代处理)
//                final Set<String> permitSet = loginUser.getPermitSet();
//                if (CollectionUtil.isNotEmpty(permitSet)) {
//                    authoritySet = permitSet.stream()
//                            .map(permit -> new SimpleGrantedAuthority(permit))
//                            .collect(Collectors.toSet());
//                }
//                //构造安全上下文所需的对象信息
//                Authentication authentication = new UsernamePasswordAuthenticationToken(loginUser.getUsername(), "", authoritySet);
//                //设置SpringSecurity的安全上下文(不设置将导致无法访问接口)
//                SecurityContextHolder.getContext().setAuthentication(authentication);

                //设置登录信息到用户工具里(供业务代码获取用户使用)
                LoginUserUtils.setUser(loginUser);
            }

            //执行过滤
            filterChain.doFilter(request, response);

        } catch (Exception e) {
            log.error("过滤器异常={}", e.getMessage(),e);
            //设置json响应数据
            response.setCharacterEncoding("UTF-8");
            response.setContentType("application/json; charset=utf-8");
            PrintWriter out = response.getWriter();
            //如果是自定义的异常的话,就使用其返回的提示信息
            if (e instanceof CustomException) {
                out.append(JSONObject.toJSONString(ResultVO.error(e.getMessage())));
            } else {
                out.append(JSONObject.toJSONString(ResultVO.error("系统繁忙...")));
            }
        }
    }

}
